package com.knife.file.domain.service.impl.minio;

import com.knife.common.exception.CommonException;
import com.knife.file.domain.entity.KnifeFileInfo;
import com.knife.file.domain.service.KnifeFileService;
import io.minio.*;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;

/**
 * minio实现文件上传下载
 *
 * @author： 76875
 * @date： 2022/4/6 星期三 18:44
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
public class KnifeMinioFileServiceImpl extends KnifeFileService {
    public static final String ERROR_UPLOAD_FILE = "上传文件失败";
    private MinioClient client;


    /**
     * 获取minio连接客户端
     *
     * @return minio连接客户端
     */
    private MinioClient getClient() {
        if (this.client == null) {
            MinioClient.Builder builder = MinioClient.builder()
                    .endpoint(config.getEndPoint())
                    .credentials(config.getAccessKeyId(), config.getAccessKeySecret());
            this.client = builder.build();
        }
        return this.client;
    }

    private void checkAndCreateBucket(String realBucketName) throws Exception {
        if (!this.getClient().bucketExists(BucketExistsArgs.builder().bucket(realBucketName).build())) {
            this.getClient().makeBucket(MakeBucketArgs.builder().bucket(realBucketName).build());
        }
        this.getClient().setBucketPolicy(SetBucketPolicyArgs.builder()
                .bucket(realBucketName)
                .config(getBucketPolicy(realBucketName))
                .build());
    }

    private String getBucketPolicy(String bucketName) {
        String s = "{\n" +
                "    \"Version\": \"2012-10-17\",\n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Effect\": \"Allow\",\n" +
                "            \"Principal\": {\n" +
                "                \"AWS\": [\n" +
                "                    \"*\"\n" +
                "                ]\n" +
                "            },\n" +
                "            \"Action\": [\n" +
                "                \"s3:GetBucketLocation\",\n" +
                "                \"s3:ListBucket\",\n" +
                "                \"s3:ListBucketMultipartUploads\"\n" +
                "            ],\n" +
                "            \"Resource\": [\n" +
                "                \"arn:aws:s3:::" + bucketName + "\"\n" +
                "            ]\n" +
                "        },\n" +
                "        {\n" +
                "            \"Effect\": \"Allow\",\n" +
                "            \"Principal\": {\n" +
                "                \"AWS\": [\n" +
                "                    \"*\"\n" +
                "                ]\n" +
                "            },\n" +
                "            \"Action\": [\n" +
                "                \"s3:ListMultipartUploadParts\",\n" +
                "                \"s3:PutObject\",\n" +
                "                \"s3:AbortMultipartUpload\",\n" +
                "                \"s3:DeleteObject\",\n" +
                "                \"s3:GetObject\"\n" +
                "            ],\n" +
                "            \"Resource\": [\n" +
                "                \"arn:aws:s3:::" + bucketName + "/*\"\n" +
                "            ]\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        return s;
        //StringBuilder builder = new StringBuilder();
        //builder.append("{\n");
        //builder.append("    \"Statement\": [\n");
        //builder.append("        {\n");
        //builder.append("            \"Action\": [\n");
        //builder.append("                \"s3:GetBucketLocation\",\n");
        //builder.append("                \"s3:ListBucket\"\n");
        //builder.append("            ],\n");
        //builder.append("            \"Effect\": \"Allow\",\n");
        //builder.append("            \"Principal\": \"*\",\n");
        //builder.append("            \"Resource\": \"arn:aws:s3:::").append(bucketName).append("\"\n");
        //builder.append("        },\n");
        //builder.append("        {\n");
        //builder.append("            \"Action\": \"s3:GetObject\",\n");
        //builder.append("            \"Effect\": \"Allow\",\n");
        //builder.append("            \"Principal\": \"*\",\n");
        //builder.append("            \"Resource\": \"arn:aws:s3:::").append(bucketName).append("/myobject*\"\n");
        //builder.append("        }\n");
        //builder.append("    ],\n");
        //builder.append("    \"Version\": \"2012-10-17\"\n");
        //builder.append("}\n");
        //return builder.toString();
    }

    @Override
    public String upload(KnifeFileInfo file, String filePath) {
        String realBucketName = this.getRealBucketName(file.getBucketName());
        String fileKey = file.getFileKey();
        try {
            this.checkAndCreateBucket(realBucketName);
            this.getClient().uploadObject(UploadObjectArgs.builder()
                    .contentType(file.getFileType())
                    .filename(filePath)
                    .bucket(realBucketName)
                    .object(fileKey)
                    .build());
            return this.getObjectPrefixUrl(realBucketName) + fileKey;
        } catch (Exception e) {
            try {
                this.getClient().removeObject(RemoveObjectArgs.builder()
                        .bucket(realBucketName)
                        .object(fileKey).build());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            throw new CommonException(ERROR_UPLOAD_FILE+e.getMessage());
        }
    }

    @Override
    public String upload(KnifeFileInfo file, InputStream inputStream) {
        String realBucketName = this.getRealBucketName(file.getBucketName());
        String fileKey = file.getFileKey();
        try {
            this.checkAndCreateBucket(realBucketName);
            this.getClient().putObject(PutObjectArgs.builder()
                    .contentType(file.getFileType())
                    .stream(inputStream, file.getFileSize(), -1)
                    .bucket(realBucketName)
                    .object(fileKey)
                    .build());
            return this.getObjectPrefixUrl(realBucketName) + fileKey;
        } catch (Exception e) {
            try {
                this.getClient().removeObject(RemoveObjectArgs.builder()
                        .bucket(realBucketName)
                        .object(fileKey).build());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            throw new CommonException(ERROR_UPLOAD_FILE+e.getMessage());
        }
    }

    @Override
    public String copyFile(KnifeFileInfo file, String oldFileKey, String oldBucketName) {
        return null;
    }

    @Override
    public void deleteFile(String bucketName, String url, String fileKey) {

    }

    @Override
    public String getSignedUrl(HttpServletRequest servletRequest, String bucketName, String url, String fileKey, String fileName, boolean download, Long expires) {
        return null;
    }

    @Override
    public void download(HttpServletRequest request, HttpServletResponse response, String bucketName, String url, String fileKey) {

    }

    @Override
    public void decryptDownload(HttpServletRequest request, HttpServletResponse response, String bucketName, String url, String fileKey, String password) {

    }

    @Override
    public String getObjectPrefixUrl(String realBucketName) {
        return String.format("%s/%s/", StringUtils.isNotBlank(this.config.getDomain()) ? this.config.getDomain() : this.config.getEndPoint(), realBucketName);
    }

}
